package com.ls;

import org.junit.Test;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;

/**
 * RandomAccessFile
 * 即使输入流,又是输出流
 */
public class RandomAccessFileTest {

    @Test
    public void read() throws Exception {
        File file = new File("E:\\s\\A.txt");
        RandomAccessFile raf = new RandomAccessFile(file, "r");

        //跳过5个字节
        raf.seek(5);//绝对位置(seek:寻找)
        raf.skipBytes(5);//相对位置

        byte[] bytes = new byte[1024 * 4];
        int read = raf.read(bytes);
        int read2 = raf.read(bytes);
        System.out.println(read);
        System.out.println(read2);

    }


    @Test
    public void write() throws Exception {
        File file = new File("E:\\t\\A.txt");
        RandomAccessFile raf = new RandomAccessFile(file, "rw");

        //覆写对应位置的数据
        raf.write("老刘".getBytes(StandardCharsets.UTF_8));

    }

    @Test
    public void testThread() throws Exception {

        File file = new File("E:\\s\\A.txt");


        //开启5个线程
        int threadNum = 5;
        //分成5份,math.ceil向上取整 5.1 = 6.0
        int part = (int) Math.ceil(file.length() / threadNum);


        List<Thread> list = new ArrayList<>();

        //断点续传
        final Map<Integer, Integer> map = new ConcurrentHashMap<>();

        //读取记录文件数据
        BufferedReader reader = new BufferedReader(new FileReader("E:\\t\\A.log"));
        String data = reader.readLine();
        String[] $data = null;
        if (new File("E:\\t\\A.log").exists()) {
            $data = data.split(",");
            reader.close();
        }

        final String[] _data = $data;
        for (int i = 0; i < threadNum; i++) {
            final int k = i;
            Thread thread = new Thread(() -> {
                RandomAccessFile log = null;
                try {
                    RandomAccessFile in = new RandomAccessFile(file, "r");
                    RandomAccessFile out = new RandomAccessFile("E:\\t\\A.txt", "rw");
                    //断点续传,用于记录完成量
                    log = new RandomAccessFile("E:\\t\\A.log", "rw");

                    //从指定位置读
                    in.seek(_data == null ? k * part : Integer.parseInt(_data[k]));
                    out.seek(_data == null ? k * part : Integer.parseInt(_data[k]));

                    byte[] bytes = new byte[8];

                    //len 每次读到的字节; plen 本线程读到的字节数
                    int len = -1, plen = 0;
                    while (true) {
                        len = in.read(bytes);
                        if (len == -1) {
                            break;
                        }
                        plen += len;
                        //记录线程已经读取的字节索引位置
                        map.put(k, plen + (_data == null ? k * part : Integer.parseInt(_data[k])));
                        out.write(bytes, 0, len);
                        //将map中的数据,进行写入
                        log.seek(0);
                        StringJoiner joiner = new StringJoiner(",");
                        map.forEach((key, val) -> joiner.add(String.valueOf(val)));
                        log.write(joiner.toString().getBytes(StandardCharsets.UTF_8));
                        if (plen + (_data == null ? k * part : Integer.parseInt(_data[k])) >= (k + 1) * part) {
                            break;
                        }
                    }


                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (log != null) {
                        try {
                            log.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            thread.start();
            list.add(thread);
        }


        long l = System.currentTimeMillis();
        for (Thread thread : list) {
            thread.join();//将线程加入,并阻塞主线程
        }
        //删除记录文件
        new File("E:\\t\\A.log").delete();
        System.out.println(System.currentTimeMillis() - l);

    }
}
